<template>
	<view class="draggable-list" :style="listStyle">
		<view v-for="(item, index) of localList" :key="item.id" class="draggable-item" :style="getItemStyle(index)">
			<view class="item-content">
				<view class="item-main">
					<image v-if="item.icon" :src="item.icon" class="item-icon"></image>
					<text class="item-text">{{ item.text }}</text>
				</view>
				<view class="right-area">
					<view class="drag-handle" @touchstart.stop="touchStart($event, index)" @touchmove.stop="touchMove" @touchend.stop="touchEnd">
						<text class="drag-icon">≡</text>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
export default {
	name: 'DraggableList',
	props: {
		list: {
			type: Array,
			required: true
		}
	},
	data() {
		return {
			localList: [],
			dragIndex: -1,
			startY: 0,
			currentY: 0,
			isDragging: false,
			itemHeight: 0,
			listHeight: 0,
			moveList: [],
			listTop: 0,
			lastToIndex: -1,
			lastMovingDirection: null
		};
	},
	computed: {
		listStyle() {
			return {
				height: `${this.listHeight}px`
			};
		}
	},
	watch: {
		list: {
			immediate: true,
			handler(newVal) {
				this.localList = JSON.parse(JSON.stringify(newVal));
				this.$nextTick(() => {
					this.initMoveList();
				});
			}
		}
	},
	mounted() {
		this.$nextTick(() => {
			this.initMeasurements();
		});
	},
	methods: {
		initMoveList() {
			this.moveList = this.localList.map((_, index) => ({
				y: index * this.itemHeight,
				moving: false
			}));
			this.listHeight = this.itemHeight * this.localList.length;
		},

		initMeasurements() {
			const query = uni.createSelectorQuery().in(this);
			query
				.select('.draggable-list')
				.boundingClientRect((data) => {
					if (data) {
						this.listTop = data.top;
					}
				})
				.exec();

			query
				.select('.draggable-item')
				.boundingClientRect((data) => {
					if (data) {
						this.itemHeight = data.height;
						this.initMoveList();
					}
				})
				.exec();
		},

		touchStart(e, index) {
			this.isDragging = true;
			this.dragIndex = index;
			this.startY = e.touches[0].clientY - this.moveList[index].y;
			this.currentY = this.moveList[index].y;
			this.moveList[index].moving = true;
		},

		touchMove(e) {
			if (!this.isDragging) return;

			const touchY = e.touches[0].clientY - this.listTop;

			// 保存上一次的位置用于判断方向
			const previousY = this.currentY;

			// 限制拖动范围在列表内
			this.currentY = Math.max(0, Math.min(touchY - this.startY + this.listTop, this.listHeight - this.itemHeight));

			const rawTargetIndex = this.currentY / this.itemHeight;
			const targetIndex = Math.round(rawTargetIndex);

			if (targetIndex >= 0 && targetIndex < this.localList.length && targetIndex !== this.dragIndex && Math.abs(rawTargetIndex - targetIndex) < 0.5) {
				// 检测拖动方向变化
				const movingDirection = this.currentY - previousY > 0 ? 'down' : 'up';

				// 移除方向改变时重置所有元素状态的逻辑
				this.lastMovingDirection = movingDirection;

				this.updateItemsPosition(this.dragIndex, targetIndex);
			}
		},

		touchEnd() {
			if (!this.isDragging) return;

			const rawTargetIndex = this.currentY / this.itemHeight;
			const floorIndex = Math.floor(rawTargetIndex);
			const offsetPercentage = rawTargetIndex - floorIndex;

			let finalIndex;
			if (offsetPercentage > 0.5) {
				finalIndex = floorIndex + 1;
			} else {
				finalIndex = floorIndex;
			}

			finalIndex = Math.max(0, Math.min(finalIndex, this.localList.length - 1));

			if (finalIndex !== this.dragIndex) {
				const item = this.localList.splice(this.dragIndex, 1)[0];
				this.localList.splice(finalIndex, 0, item);
				this.$emit('update', [...this.localList]);
			}

			// 完全重置所有元素的状态
			this.moveList = this.localList.map((_, index) => ({
				y: index * this.itemHeight,
				moving: false,
				animating: false // 确保动画状态也被重置
			}));

			// 重置所有状态变量
			this.isDragging = false;
			this.dragIndex = -1;
			this.currentY = 0;
			this.lastToIndex = -1;
			this.lastMovingDirection = null;
			this.startY = 0; // 重置起始位置

			// 使用 nextTick 确保视图更新后重新初始化
			this.$nextTick(() => {
				// 重新初始化移动列表
				this.initMoveList();
			});
		},

		updateItemsPosition(fromIndex, toIndex) {
			if (this.lastToIndex === toIndex) return;

			const previousToIndex = this.lastToIndex;
			this.lastToIndex = toIndex;

			const positions = this.moveList.map((item, index) => {
				// 被拖动的元素
				if (index === fromIndex) {
					return {
						...item,
						y: this.currentY,
						moving: true,
						animating: false
					};
				}

				let newY = index * this.itemHeight;
				let shouldAnimate = false;

				// 确定哪些元素需要移动
				if (fromIndex < toIndex) {
					if (index > fromIndex && index <= toIndex) {
						newY = (index - 1) * this.itemHeight;
						shouldAnimate = true;
					}
				} else if (fromIndex > toIndex) {
					if (index >= toIndex && index < fromIndex) {
						newY = (index + 1) * this.itemHeight;
						shouldAnimate = true;
					}
				}

				// 保持现有的动画状态，只在位置真正改变时更新
				const currentPosition = this.moveList[index];
				const positionChanged = currentPosition.y !== newY;

				return {
					...item,
					y: newY,
					moving: false,
					animating: positionChanged
				};
			});

			this.moveList = positions;
		},

		getItemStyle(index) {
			const moveData = this.moveList[index];
			const isDraggingItem = index === this.dragIndex;

			return {
				transform: `translateY(${isDraggingItem ? this.currentY : moveData?.y}px)`,
				transition: moveData?.moving ? 'none' : 'transform 0.3s ease',
				zIndex: isDraggingItem ? 2 : 1,
				boxShadow: isDraggingItem ? '0 2px 10px rgba(0,0,0,0.1)' : 'none',
				pointerEvents: 'auto' // 确保所有元素都可以接收事件
			};
		}
	}
};
</script>

<style scoped>
.draggable-list {
	width: 100%;
	position: relative;
	padding: 20rpx;
	box-sizing: border-box;
}

.draggable-item {
	padding: 20rpx;
	background: #fff;
	position: absolute;
	width: 100%;
	left: 0;
	box-sizing: border-box;
	will-change: transform;
	border-bottom: 2rpx solid #eeeeee;
}

.item-content {
	display: flex;
	align-items: center;
	justify-content: space-between;
}

.item-main {
	display: flex;
	align-items: center;
	flex: 1;
}

.item-icon {
	width: 40rpx;
	height: 40rpx;
	margin-right: 20rpx;
}

.item-text {
	font-size: 28rpx;
}

.drag-handle {
	padding: 0 20rpx;
	cursor: move;
}

.drag-icon {
	font-size: 48rpx;
	color: #999;
}
</style>
